package de.bazinga.rotw.network;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Vector;

import com.captiveimagination.jgn.JGN;
import com.captiveimagination.jgn.clientserver.JGNClient;
import com.captiveimagination.jgn.synchronization.SynchronizationManager;
import com.captiveimagination.jmenet.JMEGraphicalController;
import com.jme.scene.Spatial;
import com.jmex.game.state.GameStateManager;

import de.bazinga.rotw.collision.CollidableObjects;
import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.menu.InfoMenu;
import de.bazinga.rotw.menu.LoadingState;
import de.bazinga.rotw.network.message.RegisterMessages;
import de.bazinga.rotw.network.message.SynchronizeCreatePlayerMessage;
import de.bazinga.rotw.network.message.physics.UpdatePhysicsMessage;
import de.bazinga.rotw.objects.elevator.Elevator;
import de.bazinga.rotw.objects.elevator.ElevatorMessage;
import de.bazinga.rotw.person.Person;
import de.bazinga.rotw.util.NetworkConstants;
import de.bazinga.rotw.vehicle.Vehicle;
import de.bazinga.rotw.vehicle.VehicleDamageMessage;

public class Client extends BasicSyncManager {
	
	private JGNClient client = null;
	
	private SynchronizationManager syncManager = null;
	

	public Client(RotwGameState gameClient, String ipString) throws Exception {
		// Register Messages
		RegisterMessages.registerMessages();
		
		 // Initialize networking
		// works with internet-address!
		InetSocketAddress serverReliable = null;
		InetSocketAddress serverFast = null;
		if(!ipString.equals("")) {
			serverReliable = new InetSocketAddress(InetAddress.getByName(ipString), NetworkConstants.SERVER_TCP_PORT);
	        serverFast = new InetSocketAddress(InetAddress.getByName(ipString), NetworkConstants.SERVER_UDP_PORT);
		}else{
			serverReliable = new InetSocketAddress(InetAddress.getLocalHost(), NetworkConstants.SERVER_TCP_PORT);
	        serverFast = new InetSocketAddress(InetAddress.getLocalHost(), NetworkConstants.SERVER_UDP_PORT);
		}
	     
        // Initialize networking
        InetSocketAddress clientReliable = new InetSocketAddress(InetAddress.getLocalHost(), 0);
        InetSocketAddress clientFast = new InetSocketAddress(InetAddress.getLocalHost(), 0);
        client = new JGNClient(clientReliable, clientFast);
        
        JGN.createThread(client).start();
        
        // Instantiate an instance of a JMEGraphicalController
        JMEGraphicalController controller = new JMEGraphicalController();
        
        // Create SynchronizationManager instance for this server
        syncManager = new SynchronizationManager(client, controller);
        syncManager.addSyncObjectManager(this);
        JGN.createThread(syncManager).start();
        
        setScene(gameClient.getRootNode());
        
        // Connect to the server before we register anything
        System.out.println("Connecting!");
        
        
        
        ClientMapListener mapListener = new ClientMapListener();
        client.addMessageListener(mapListener);
        
        try{
        	client.connectAndWait(serverReliable, serverFast, 5000);
        }catch(IOException e) {
        	// handle exception
        	((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setRunning(false);
        	((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setActive(false);
        	
        	client.disconnect();
        	client.close();
        	
        	((LoadingState)GameStateManager.getInstance().getChild("loadingMenu")).setActive(false);
        	((InfoMenu)GameStateManager.getInstance().getChild("infoMenu")).setInfoText("Couldnt Connect");
        	((InfoMenu)GameStateManager.getInstance().getChild("infoMenu")).setActive(true);
        	return ;
        }

        System.out.println("Connected!");
        
        client.removeMessageListener(mapListener);
        client.getServerConnection().getReliableClient().addMessageListener(new ClientMessageListener(gameClient));
        
        // Register server vehicle
        SynchronizeCreatePlayerMessage scm = new SynchronizeCreatePlayerMessage();
        scm.setSyncObjectType(NetworkConstants.OBJ_PLAYER);
        scm.setPlayerName(gameClient.getPlayer().getPlayerName());
        scm.setModelTexture(gameClient.getPlayer().getTextureColor());
        scm.setTeam(Person.TEAM_ONE);
        syncManager.register(gameClient.getPlayer(), scm, NetworkConstants.UPDATE_INTERVALL);
        
        
        
        // Get Information for Elevators
        for(Spatial s:CollidableObjects.getInstance().getObjects("gameObjects")) {
        	if(s instanceof Elevator) {
        		ElevatorMessage emsg = new ElevatorMessage();
    			emsg.setRequestInfo(true);
    			emsg.setElevatorIndex(CollidableObjects.getInstance().getObjects("gameObjects").indexOf(((Elevator)s)));
    			getClient().sendToServer(emsg);
        	}
        }
        
        // Get Information for Vehicles
        Vector<Spatial> vehicles = CollidableObjects.getInstance().getObjects("vehicle");
        if(vehicles != null) {
	        for(Spatial s:vehicles) {
	        	if(s instanceof Vehicle) {
	        		VehicleDamageMessage emsg = new VehicleDamageMessage();
	    			emsg.setRequestInformation(true);
	    			emsg.setVehicleIndex(CollidableObjects.getInstance().getObjects("vehicle").indexOf(((Vehicle)s)));
	    			getClient().sendToServer(emsg);
	        	}
	        }
        }
        
        // Update Information for Physics-Objects
        UpdatePhysicsMessage upm = new UpdatePhysicsMessage();
        getClient().sendToServer(upm);
        
        
        
        gameClient.getGameMode().initClient(getClient());
	}

	public void close() {
		try {
			client.disconnect();
			client.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public JGNClient getClient() {
		return client;
	}

	
	public SynchronizationManager getSyncManager() {
		return syncManager;
	}
}
